#include "includes_fw.h"
#include "lib_retina.h"
#include "mmpf_audio_ctl.h"
#include "mmpf_audio.h"
#include "mmpf_i2s_ctl.h"
#include "config_fw.h"
#include "mmpf_pll.h"
#include "mmp_reg_audio.h"
#include "mmps_3gprecd.h"
#if PCAM_EN==1
#include "mmpf_encapi.h"
#endif
#include "mmp_reg_usb.h"

#if (SUPPORT_MP4) || (SUPPORT_MTS)
#include "mmpf_aacencapi.h"
#endif

#if SUPPORT_UAC

//#include "maxloud.h"
/** @addtogroup MMPF_AUDIO
@{
*/
//static MMP_ULONG glAudioSamplerate = 0; //must default initialize

MMP_UBYTE    gbUseAitADC;
MMP_UBYTE    gbUseAitDAC;

MMPF_AUDIO_LINEIN_CHANNEL	m_audioLineInChannel;

MMP_UBYTE    gbAudioOutI2SFormat;
MMP_UBYTE    gbAudioInI2SFormat;

#if 1//(CHIP == P_V2)

MMP_UBYTE    gbDACDigitalGain = DEFAULT_DAC_DIGITAL_GAIN;
MMP_UBYTE    gbDACAnalogGain = DEFAULT_DAC_ANALOG_GAIN;
MMP_UBYTE    gbADCDigitalGain = DEFAULT_ADC_DIGITAL_GAIN;
MMP_UBYTE    gbADCAnalogGain = DEFAULT_ADC_ANALOG_GAIN;
MMP_UBYTE    gbDACLineOutGain = DEFAULT_DAC_LINEOUT_GAIN; 
// Test case
// 50cm, need to have -27dB volume
MMP_UBYTE    gbADCBoost =  40 ; // Change 1 or 0 to 20dB,30dB,40dB for Python_v2
#endif
MMP_BOOL     gbHasInitAitDAC = MMP_FALSE;
MMP_BOOL     gbAitADCEn = MMP_TRUE;

MMP_USHORT  gsAudioRecordState;
MMP_USHORT  gsAudioEncodeFormat;
MMP_USHORT  gsAudioRecEvent;
MMP_ULONG   glAudioEncodeLength;
AUDIO_ENC_INBUF_HANDLE AudioEncInBufHandle;

//extern short        numOutSamples;
extern MMPF_OS_FLAGID SYS_Flag_Hif;
extern MMP_USHORT gsAudioPreviewStartEnable;


//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_AACRecordIntHandler
//  Parameter   : None
//  Return Value : None
//  Description : AMR record interrupt handler
//------------------------------------------------------------------------------
#if defined(AAC_R_FW)||defined(VIDEO_AAC_R_FW)||(AAC_R_EN)||(VAAC_R_EN)

#include "mmpf_usbvend.h"
extern void uac_process_audio_data(void);
MMP_ERR MMPF_Audio_DropDataHandler(MMP_USHORT usPath)
{
    AITPS_AUD   pAUD    = AITC_BASE_AUD;
	MMP_USHORT	i,th ;
	MMP_SHORT	tmp ;//  *ptempBuf;
	th =  pAUD->I2S_FIFO_RD_TH;
		for(i = 0; i < (th>>1); i++) {
			tmp = pAUD->I2S_FIFO_DATA;
			tmp = pAUD->I2S_FIFO_DATA;
        }	
   return MMP_ERR_NONE;
}

MMP_USHORT MMPF_Audio_EncodeIntHandler(MMP_USHORT usPath)
{
    AITPS_AUD   pAUD    = AITC_BASE_AUD;
	MMP_SHORT	*pInbuf=NULL;
	MMP_USHORT	i,th ;
	pInbuf = (MMP_SHORT *)MMPF_Audio_GetWrPtr();
	th =  pAUD->I2S_FIFO_RD_TH;
	
	if (usPath == I2S_PATH) {
		for(i = 0; i < (th>>1); i++) {
			*pInbuf++ = pAUD->I2S_FIFO_DATA;
			*pInbuf++ = pAUD->I2S_FIFO_DATA;
		}
	}
	return	th;
}
#endif
#endif

//------------------------------------------------------------------------------
//  Function    : MMPF_AFE_ISR
//  Parameter   : None
//  Return Value : None
//  Description : AFE fifo isr
//------------------------------------------------------------------------------
#if SUPPORT_UAC
extern MMP_UBYTE   gbAud1stInToken ;
extern MMP_SHORT   gsAudioSamplesPerFrame,gsInAudioSamplesPerFrame ;
MMP_ULONG glI2Stick = 0;
void MMPF_AFE_ISR(void)
{
    AITPS_AUD   pAUD    = AITC_BASE_AUD;
    MMP_ULONG 	irq_src;
	MMP_USHORT 	usbin = gsAudioPreviewStartEnable;
	MMP_USHORT  wr_sample;
    
#if (MicSource==MicInPathAFE)    
	irq_src = (pAUD->AFE_FIFO_CPU_INT_EN & pAUD->AFE_FIFO_SR);
#elif (MicSource==MicInPathI2S)
	irq_src = (pAUD->I2S_FIFO_CPU_INT_EN & pAUD->I2S_FIFO_SR);	
#endif	
	if (irq_src & AUD_INT_FIFO_REACH_UNRD_TH) {

    	glI2Stick++;
        if( /*gbAud1stInToken*/ 1 ) {
	    // Processing currect frame
#if (MicSource==MicInPathAFE)    
            wr_sample = MMPF_Audio_EncodeIntHandler(AFE_PATH);
#elif (MicSource==MicInPathI2S)
            wr_sample = MMPF_Audio_EncodeIntHandler(I2S_PATH);
#endif
            if(usbin){
                MMPF_Audio_UpdateWrPtr(wr_sample);
#if (SUPPORT_AUDIO_PROCESSING_TASK)                
                if( MMPF_Audio_GetSizeByType(SIZE_CAN_PR)  >= (gsAudioSamplesPerFrame*PRC_SAMPLES_TIME << 1)) {
        #if 0
                    // signal audio processing task to do MMPF_Audio_EncodeFrame()
                    gsAudioRecEvent |= EVENT_FIFO_OVER_THRESHOLD;
                    MMPF_OS_SetFlags(SYS_Flag_Hif, SYS_FLAG_AUDIOREC, MMPF_OS_FLAG_SET);
        #else
                    MMPF_Audio_EncodeFrame();
        #endif
                }
#else
                // if there is no 
                MMPF_Audio_EncodeFrame();
#endif                
                //dbg_printf(3,"ws= %d\r\n", wr_sample);
            }
        } 
        else {
        #if (MicSource==MicInPathAFE)    
            MMPF_Audio_DropDataHandler(AFE_PATH);
        #elif (MicSource==MicInPathI2S)
            MMPF_Audio_DropDataHandler(I2S_PATH);
        #endif
        }
	}
}
#else
void    MMPF_AFE_ISR(void)
{
}
#endif

#if SUPPORT_UAC
//------------------------------------------------------------------------------
//  Function    : MMPF_InitAudioSetting
//  Parameter   :
//          path--specify audio path
//       samprate--sampleing rate
//  Return Value : AUDIO_NO_ERROR
//  Description : Init codec
//------------------------------------------------------------------------------
MMP_USHORT  MMPF_InitAudioSetting(MMP_USHORT path,int samprate)
{
    switch (path) {
		#if (I2S_OUT_EN == 1)
        case I2S_OUT:
            MMPF_SetI2SFreq(samprate);
            if (gbAudioOutI2SFormat) {
                MMPF_SetI2SMode(I2S_I2S_MODE, LEFT_CHANNEL_LOW, I2S_OUTPUT_24_BITS);
                MMPF_PresetI2S(I2S_OUT,I2S_SLAVE_MODE,8);
            } else {
                MMPF_SetI2SMode(I2S_STD_MODE, LEFT_CHANNEL_LOW, I2S_OUTPUT_16_BITS);
                MMPF_PresetI2S(I2S_OUT,I2S_MASTER_MODE,16);
            }
            break;
        #endif
        case I2S_IN:
            MMPF_SetI2SFreq(samprate);
            if(gbAudioInI2SFormat){//0 -> master , 1 ->slave
                MMPF_SetI2SMode(I2S_I2S_MODE, LEFT_CHANNEL_LOW, I2S_OUTPUT_16_BITS);
        #if (AUDEXT_DAC == AIC3254) || (AUDEXT_DAC == CX20709)
                MMPF_PresetI2S(I2S_IN,I2S_SLAVE_MODE,1);  // tomy@2010_12_23, to support one bit clock cycle delay for CX20709
        #else
                MMPF_PresetI2S(I2S_IN,I2S_SLAVE_MODE,0);
        #endif
            }else{
                MMPF_SetI2SMode(I2S_STD_MODE, LEFT_CHANNEL_LOW, I2S_OUTPUT_16_BITS);
                MMPF_PresetI2S(I2S_IN,I2S_MASTER_MODE,0);
//                MMPF_PresetI2S(I2S_IN,I2S_MASTER_MODE,1);  // tomy@2010_12_23, to support one bit clock cycle delay for CX20709
            }
            break;
    }
    return  AUDIO_NO_ERROR;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_InitializePlayFIFO
//  Parameter   :
//          path-- select path
//          threshold -- fifo int threshold
//  Return Value : None
//  Description : Init Audio Output Fifo
//------------------------------------------------------------------------------
MMP_ERR    MMPF_Audio_InitializePlayFIFO(MMP_USHORT usPath, MMP_USHORT usThreshold)
{
    #if (I2S_OUT_EN == 1)
    AITPS_AUD   pAUD    = AITC_BASE_AUD;
    MMP_ULONG    i;

    switch (usPath) {
	case I2S_OUT:
		pAUD->I2S_FIFO_RST = AUD_FIFO_RST_EN;
		pAUD->I2S_FIFO_RST = 0;

		pAUD->I2S_FIFO_WR_TH = usThreshold;
		for (i = 0; i< 256; i++)
			pAUD->I2S_FIFO_DATA = 0;
		break;
    }
    #endif

	return MMP_ERR_NONE;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetMux
//  Parameter   :
//          path--select path
//          bEnable--1:enable;0:disable
//  Return Value : MMP_ERR_NONE
//  Description : Set audio mux
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetMux(MMP_USHORT path, MMP_BOOL bEnable)
{
    AITPS_AUD   pAUD    = AITC_BASE_AUD;

    switch (path) {
        #if (I2S_OUT_EN == 1)
        case I2S_OUT:
            if (bEnable) {
                //Removed by Truman for surpress the pause message
                //RTNA_DBG_Str2("MMPF_Audio_SetMux I2S_out\r\n");
                pAUD->I2S_FIFO_CPU_INT_EN = AUD_INT_FIFO_REACH_UNWR_TH;
                pAUD->I2S_MUX_MODE_CTL = AUD_MUX_AUTO;
                pAUD->I2S_CPU_INT_EN = AUD_INT_EN;
            }
            else {
                pAUD->I2S_FIFO_CPU_INT_EN = 0;
                pAUD->I2S_MUX_MODE_CTL = AUD_MUX_CPU;
                pAUD->I2S_CPU_INT_EN = AUD_INT_DIS;
                //2005-05-23 : for video play "bobo" noise. some melody IC can't accept turn
                // on/off i2s clock too fast.
                //I2S_BASE_L[I2S_GENERAL_CTL_L] = I2S_DISABLE;
            }
            break;
        #endif
        #if (MicSource==MicInPathI2S)  
        case I2S_IN:
            if (bEnable) {
                //RTNA_DBG_Str(0,"MMPF_Audio_SetMux I2S_IN\r\n");
                pAUD->I2S_FIFO_CPU_INT_EN = AUD_INT_FIFO_REACH_UNRD_TH | AUD_INT_FIFO_FULL;
                pAUD->I2S_MUX_MODE_CTL = AUD_MUX_AUTO;
                pAUD->I2S_CPU_INT_EN = AUD_INT_EN;
                //pAUD->AFE_MUX_MODE_CTL = 0 ;   //Gason@add for I2S input             
            }
            else {
                pAUD->I2S_FIFO_CPU_INT_EN = 0;
                pAUD->I2S_MUX_MODE_CTL = AUD_MUX_CPU;
                pAUD->I2S_CPU_INT_EN = AUD_INT_DIS;
            }
            break;
        #endif    
    }
    return  MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_InitializeEncodeFIFO
//  Parameter   :
//          path-- select path
//          threshold -- fifo int threshold
//  Return Value : None
//  Description : Init audio input fifo
//------------------------------------------------------------------------------
MMP_ERR	MMPF_Audio_InitializeEncodeFIFO(MMP_USHORT usPath, MMP_USHORT usThreshold)
{
    AITPS_AUD   pAUD    = AITC_BASE_AUD;

    switch (usPath) {
    #if (MicSource==MicInPathI2S)  
	case I2S_IN:
		pAUD->I2S_FIFO_RST = AUD_FIFO_RST_EN;
		pAUD->I2S_FIFO_RST = 0;
		pAUD->I2S_FIFO_RD_TH = usThreshold;
        break;
    #endif    
    }
	return MMP_ERR_NONE;

}
//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetEncodeLength
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetEncodeLength(MMP_ULONG ulFileLimit)
{
	glAudioEncodeLength = ulFileLimit;

    return  MMP_ERR_NONE;
}

#if 0
//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetDACDigitalGain
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetDACDigitalGain(MMP_UBYTE gain)
{
    return  MMP_ERR_NONE;
}


//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetDACAnalogGain
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetDACAnalogGain(MMP_UBYTE gain)
{
    return  MMP_ERR_NONE;
}
#endif

#if(MicSource == MicInPathAFE)
//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetADCDigitalGain
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetADCDigitalGain(MMP_UBYTE gain)
{
    return  MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetADCAnalogGain
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetADCAnalogGain(MMP_UBYTE gain, MMP_UBYTE boostdb)
{
    return  MMP_ERR_NONE;
}
#endif

//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetEncodeFormat
//  Parameter   :
//              mode :the audio record mode
//  Return Value : None
//  Description : Set the audio record mode
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetEncodeFormat(MMP_USHORT mode)
{
    gsAudioEncodeFormat = mode;
    //RTNA_DBG_PrintLong(0, gsAudioEncodeFormat);

    return  MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_SetVoiceInPath
//  Parameter   : None
//  Return Value : None
//  Description : Set Voice In Path
//------------------------------------------------------------------------------
MMP_USHORT  MMPF_SetVoiceInPath(MMP_UBYTE path)
{
    return  AUDIO_NO_ERROR;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetLineInChannel
//  Parameter   : None
//  Return Value : None
//  Description : Set Voice In Path
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetLineInChannel(MMPF_AUDIO_LINEIN_CHANNEL lineinchannel)
{
	m_audioLineInChannel = lineinchannel;

    return  MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_SetAudioOutPath
//  Parameter   : None
//  Return Value : None
//  Description : Set Voice In Path
//------------------------------------------------------------------------------
MMP_USHORT  MMPF_SetAudioOutPath(MMP_UBYTE path)
{
    return  AUDIO_NO_ERROR;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetI2SOutFormat
//  Parameter   : None
//  Return Value : None
//  Description : Set audio out i2s format
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetI2SOutFormat(MMP_UBYTE ubFormat)
{
    gbAudioOutI2SFormat = ubFormat;

    return  MMP_ERR_NONE;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetI2SInFormat
//  Parameter   : None
//  Return Value : None
//  Description : Set audio in i2s format
//------------------------------------------------------------------------------
MMP_ERR  MMPF_Audio_SetI2SInFormat(MMP_UBYTE ubFormat)
{
    gbAudioInI2SFormat = ubFormat;

    return  MMP_ERR_NONE;
}

#if 0
//------------------------------------------------------------------------------
//  Function    : MMPF_InitAitADC
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
MMP_USHORT  MMPF_InitAitADC(MMP_ULONG samplerate)
{
    return  AUDIO_NO_ERROR;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_InitAitCodec
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------
MMP_USHORT  MMPF_InitAitCodec(MMP_ULONG samplerate)
{
    return  AUDIO_NO_ERROR;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Audio_SetPLL
//  Parameter   : 
//      ulSamplerate -- sampling rate
//  Return Value : None
//  Description : Dynamic change PLL for audio DAC.
//------------------------------------------------------------------------------
MMP_ERR MMPF_Audio_SetPLL(MMP_ULONG ulSamplerate)
{
    MMP_ERR         err;
    MMPF_PLL_MODE   pll_mode;
    if (glAudioSamplerate != ulSamplerate) {
        switch(ulSamplerate) {
        case 48000:
            pll_mode = MMPF_PLL_AUDIO_48K;
            break;
        case 44100:
            pll_mode = MMPF_PLL_AUDIO_44d1K;
            break;
        case 32000:
            pll_mode = MMPF_PLL_AUDIO_32K;
            break;
        case 22050:
            pll_mode = MMPF_PLL_AUDIO_22d05K;
            break;
        case 16000:
            pll_mode = MMPF_PLL_AUDIO_16K;
            break;
        case 12000:
            pll_mode = MMPF_PLL_AUDIO_12K;
            break;
        case 11025:
            pll_mode = MMPF_PLL_AUDIO_11d025K;
            break;
        case 8000:
            pll_mode = MMPF_PLL_AUDIO_8K;
            break;
        default:
            RTNA_DBG_Str0("Unsupported audio sample rate!\r\n");
            return MMP_AUDIO_ERR_PARAMETER;
            break;
        }
        err = MMPF_PLL_Setting(pll_mode, MMP_TRUE);
        if (err != MMP_ERR_NONE)
            return err;
        glAudioSamplerate = ulSamplerate;
    }

    return MMP_ERR_NONE;
}

MMP_USHORT  MMPF_SetAFEFreq(MMP_ULONG samplerate)
{
    return AUDIO_NO_ERROR;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_CloseDac
//  Parameter   : None
//  Return Value : None
//  Description :
//------------------------------------------------------------------------------		
MMP_USHORT MMPF_CloseDAC(void)
{
    return  AUDIO_NO_ERROR;
}
#endif

MMP_USHORT MMPF_CloseADC(void)
{
    return  AUDIO_NO_ERROR;
}

#endif

/** @} */ // end of MMPF_AUDIO
